<template>
   <section class="action">
      <a-button type="primary" danger style="margin-right:25px " :icon="h(ChromeOutlined )" @click="handleTranslate">原文处理并翻译</a-button>
      <a-button type="primary" style="margin-right:25px " :icon="h(ChromeOutlined )" @click="handleRow">原文处理</a-button>
      <a-button  :icon="h(ZoomInOutlined)" v-if="preview" @click="preview=!preview">预览</a-button>
      <a-button :icon="h(EditOutlined  )" v-else @click="preview=!preview">编辑</a-button>
      <a-select
          v-model:value="metadata.publisher"
          label-in-value
          style="width: 160px;margin-left:25px"
          :options="PressOptions"
      ></a-select>
     <a-button  style="margin-left:25px " type="primary"    :icon="h(ChromeOutlined )" @click="handletranslateNcx">翻译ncx</a-button>
     <a-button type="primary"   style="margin:0 25px " :icon="h(ChromeOutlined )" @click="handleExport">导出</a-button>
      <span class="fixed">
    </span>
      <span>
      本书大约
      <span class="countNumber">
       {{countNumber}}
      </span>
      个字符
    </span>
    </section>
  <a-spin :spinning="spinning">
    <main>
      <section ref="nav" class="nav">
        <div
            v-if="docList.length>0"
            :class="'title '+(bookIndex===index?'select':'')"
            v-for="(doc,index) in  docList"
            :key="index"
            @click="handleTitle(index)"
        >
          {{doc.title}}
        </div>
      </section>
      <section ref="htmlContent"
               :contenteditable="preview"
               class="html_content"
               @input="updateContent"
               v-html="doc.content">

      </section>
      <section class="tableList" ref="tableList">
        <section v-if="doc.tables.length>0">
          <a-button  type="primary" style="margin: 10px  " @click="handleAllTable()">
            所有表格不翻译
          </a-button>
          <a-button danger type="primary" style="margin: 0 10px  " @click="handleAllTableRemove()">
            所有表格翻译
          </a-button>
        </section>
        <div v-for="(table,index) in doc.tables" :key="table.id" :tagid="table.id" class="table_wrapper">
          <div class="table_operate">
            <a-button type="primary" style="margin: 10px 0 " @click="handleAll(table.tableConfig)">
              全部不翻译
            </a-button>
            <a-button danger type="primary" style="margin: 0 10px  " @click="handleAllRemove(table.tableConfig)">
              全部翻译
            </a-button>
            <a-table size="small" :columns="columns" :dataSource="table.tableConfig">
              <template #bodyCell="{ column, record }">
                <template v-if="column.key === 'columnIndex'">
              <span>
                {{ record.columnIndex +1 }}
              </span>
                </template>
                <template v-if="column.key === 'language'">
                  <a-select
                      v-model:value="record.language"
                      :options="options"
                  ></a-select>
                </template>
              </template>
            </a-table>
          </div>
          <div v-html="table.tableContent"  v-if="!spinning">
          </div>

        </div>
      </section>
    </main>
  </a-spin>

</template>
<script setup>
import JsonData from './loadURL.json'
import {code} from './change_code'
import {createPre} from './create_pre'
import {v4} from 'uuid'
import {ChromeOutlined, EditOutlined, ZoomInOutlined} from '@ant-design/icons-vue';
import {computed, getCurrentInstance, h, nextTick, reactive, ref, watch} from "vue";
import JSZip from "jszip";
import ePub from "epubjs";
import {message} from "ant-design-vue";
import {XMLBuilder} from "fast-xml-parser";
import {imt} from "../../api/index.ts";


//@ts-ignore
let {ctx: that, proxy} = getCurrentInstance()
let columns = [
  {
    title: '列数',
    dataIndex: 'columnIndex',
    key: 'columnIndex',
  },
  {
    title: '第一行名称',
    dataIndex: 'line',
    key: 'line',
  },
  {
    title: '语言',
    dataIndex: 'language',
    key: 'language',
  },
];



let  spinning = ref(true)
let  options = reactive([
  {
    value: 'row',
    label: '原文',
  },
  {
    value: 'zh',
    label: '中文'
  }
])
let zipUtil = reactive({})
let  docList =  ref([])
const props = defineProps(['file'])
let  preview =  ref(false)
let  metadata =reactive({})
let  bookIndex = ref(0)
let  tableIndex = ref(0)
let  tableList = ref()
let nav = ref();
let htmlContent = ref();
let  htmlIndex = ref(0);
let  doc = reactive({
  content: "",
  title: '',
  tables: []
})

let allNavPoint  = ref([]);

let  total = ref(0);
let  PressOptions = reactive([...Object.keys(JsonData).map(item=>{
  return {
    value: item,
    label: item,
  }
})])
//本文字符数
const countNumber = computed(() => {
  return docList.value.reduce((sum, item) => sum + item.content.length, 0)
})

let    getDom  =(docListElement)=>{
  let dom = null
  const parser = new DOMParser()
  const isXML = docListElement.title.includes('.ncx')
  if (isXML){
    //xml 不做操作
  }else{
    const isXHTML = docListElement.title.includes('.xhtml')|| docListElement.content.includes('http://www.w3.org/1999/xhtml')
    if (isXHTML) {
      dom = parser.parseFromString(docListElement.content, 'application/xhtml+xml')
    } else {
      dom = parser.parseFromString(docListElement.content, 'text/html')
    }
  }
  return dom;
}

let getAllTables = (docItem) => {
  let dom = getDom(docItem)
  let tables = []
  if (!docItem.title.includes('ncx')){
    let tableList = dom.querySelectorAll("table");
    for (let i = 0; i < tableList.length; i++) {
      let table = tableList[i];
      let uuidV4 = v4();
      let querySelector = table.querySelector('thead');
      let columns =[]

      if (querySelector !=null){
         columns =  table.querySelectorAll("th")

        if (columns.length === 0){
          columns =  table.querySelectorAll("thead td")
        }

      }else{
        columns =  table.querySelectorAll("tr:first-child > td");
      }

      let tableConfig = [];
      for (let j = 0; j < columns.length; j++) {
        let item = columns[j];
        let  trSelector = `td:nth-child(${j+1})`
        let tdList = table.querySelectorAll(trSelector);

        let some = false
        for (let k = 0; k < tdList.length; k++) {
          let className = tdList[k].getAttribute("class");
          let b = className?.includes("notranslate");
          if (b === true){
            some =true
          }
        }

        tableConfig.push({
          columnIndex: j,
          language:( j ===0||some===true)?'row': 'zh',
          line: item.textContent
        })
      }
      table.setAttribute('tableId', uuidV4);
      tables.push({
        id: uuidV4,
        tableContent: table.outerHTML,
        tableConfig
      })
    }
    docItem.content = dom.documentElement.outerHTML;
  }else{
    //xml 不做操作
  }
  
  return tables;
}
//函数
let  loadBook = ()=>{
  // 读取文件为ArrayBuffer
  const reader = new FileReader();
  reader.readAsArrayBuffer(props.file);
  reader.onload =  async (e) => {

    // //处理书籍
    const book = ePub(e.target.result);
    book.loaded.metadata.then( async book => {
      metadata = book
     let params = {
        'header': {
          'fn': 'auto_translation',
          'session': '',
          'client_key': 'browser-chrome-117.0.0-Windows 10-d516eec1-9db2-4f91-b521-c1c6a75451d1-1697843573656',
          'user': ''
        },
        'type': 'plain',
        'model_category': 'normal',
        'text_domain': 'general',
        'source': {
          'lang': 'en',
          'text_list': [book.title]
        },
        'target': {
          'lang': 'zh'
        }
      }
       imt(params).then(res=>{
         metadata.title = res.auto_translation[0]

       });

      // 加载EPUB文件
      let  zip =  await JSZip.loadAsync(reader.result);
      zipUtil  =zip;
      let  tempList =[]
      for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
        // 判断文件是否是.xhtml或.html文件
        if (zipEntry.name.endsWith(".xhtml") || zipEntry.name.endsWith(".html") || zipEntry.name.endsWith(".ncx")|| zipEntry.name.endsWith(".htm")) {
          // 获取文本文件的内容
          try {
            const content = await zipEntry.async("string");
            // 加载HTML文档
            let item = {
              title: zipEntry.name,
              content: content
            }
            let allTables = getAllTables(item);
            tempList.push({
              ...item,
              tables: allTables
            })
          }catch(err){

          }
        }
      }
      docList.value.push(...tempList)
      spinning.value = false

      //显示书籍
      nextTick(()=>{
        spinning.value = false
        doc.content = docList.value[bookIndex.value].content
        doc.title = docList.value[bookIndex.value].title
        doc.tables = docList.value[bookIndex.value].tables
        spinning.value = false
        document.addEventListener('keydown', (event) => {
          // 检查按下的是向上箭头键
          if (event.key === 'ArrowUp') {
            if (bookIndex.value > 0) {
              bookIndex.value--
              updateDoc()
            }
          } else if (event.key === 'ArrowDown') {
            if (bookIndex.value < (docList.value.length-1)) {
              bookIndex.value++
              updateDoc()
            }
          }


          // 检查按下的是向上箭头键
          if (event.key === 'ArrowLeft') {
            if (tableIndex.value > 0) {
              tableIndex.value--
              let tableData = doc.tables[tableIndex.value];
              let tableId = tableData.id;
              let selector = `[tagid="${tableId}"]`;
              let table =  tableList.value.querySelector(selector);
              table.scrollIntoView({ behavior: 'smooth', block: 'start' })

            }
          } else if (event.key === 'ArrowRight') {
            if (tableIndex.value <( doc.tables.length-1)) {
              tableIndex.value++
              let tableData = doc.tables[tableIndex.value];
              let tableId = tableData.id;
              let selector = `[tagid="${tableId}"]`;
              let table =  tableList.value.querySelector(selector);
              table.scrollIntoView({ behavior: 'smooth', block: 'start' })
            }
          }


        })
      })
    })


  };
}
//主进程
let  main =()=>{
  loadBook();
}



main();






//事件函数

let  updateDoc =()=>{
  tableIndex.value = 0;
  tableList.value.scrollTop = 0;
  doc.content = docList.value[bookIndex.value].content
  doc.title = docList.value[bookIndex.value].title
  doc.tables = docList.value[bookIndex.value].tables

}

let  handleAll = (tableConfigList)=>{
  tableConfigList.forEach(item=>{
    item.language ='row'
  })
}
let  handleAllRemove = (tableConfigList)=>{
  tableConfigList.forEach(item=>{
    item.language ='zh'
  })
}

let  handleAllTable = ()=>{
  doc.tables.forEach(item=>{
    item.tableConfig.forEach(sub=>{
      sub.language ='row'
    })
  })


}
let  handleAllTableRemove = ()=>{
  doc.tables.forEach(item=>{
    item.tableConfig.forEach(sub=>{
      sub.language ='zh'
    })
  })

}


let  handleTitle =(index)=>{
  bookIndex.value =index
  updateDoc();
}

let   updateContent = (event)=>{
  let innerHTML = event.target.innerHTML;
  docList.value[bookIndex.value].content =   innerHTML
}



/**
 * 操作文本处理区域
 */
let codeType = reactive({
  tag: (tag, dom) => dom.getElementsByTagName(tag),
  selector: (selector, dom) => dom.querySelectorAll(selector),
  id: (id, dom) => dom.getElementById(id),
  className: (className, dom) => dom.getElementsByClassName(className)
})

let preType = reactive({
  tag: (tag, dom) => dom.getElementsByTagName(tag),
  selector: (selector, dom) => dom.querySelectorAll(selector),
  id: (id, dom) => dom.getElementById(id),
  className: (className, dom) => dom.getElementsByClassName(className)
})


let handleHTML = (dom) => {
  Object.entries(JsonData).forEach((item, index) => {
    const siteValue = item[1]
    if (metadata.publisher.includes(siteValue.site)) {
      Object.entries(siteValue.Code || {}).forEach(jsonItem => {
        const key = jsonItem[0]
        const value = jsonItem[1]
        value.forEach((tag) => {
          const selectedTag = codeType[key](tag, dom)
          code(selectedTag)
        })
      })
      //@ts-ignore
      Object.entries(siteValue.Pre || {}).forEach(jsonItem => {
        const key = jsonItem[0]
        const value = jsonItem[1]
        value.forEach((tag) => {
          const selectedTag = preType[key](tag, dom)
          createPre(selectedTag)
        })
      })
    }
  })
}

let  handleTranslate =()=>{
  let docListElement = docList.value[0];
  let dom = getDom(docListElement)
  handleHTML(dom)
}





let handleRow = () => {
  docList.value.forEach(item=>{
    let dom = getDom(item);
    handleHTML(dom)
  })
}





let  generateEpub =(htmlData)=>{
  //@ts-ignore
  zipUtil.forEach((relativePath, zipEntry)=> {
    // 判断文件是否是.xhtml或.html文件
    if (zipEntry.name.endsWith(".xhtml") || zipEntry.name.endsWith(".html") || zipEntry.name.endsWith(".ncx")|| zipEntry.name.endsWith(".htm")) {
      let  content =  htmlData[zipEntry.name]
      //@ts-ignore
      zipUtil?.file(zipEntry.name, content);
    }
  });
  //@ts-ignore
  zipUtil.generateAsync({ type: 'blob' }).then((updatedEpubBlob)=> {
    // 下载修改后的 EPUB 文件
    let downloadLink = document.createElement('a');
    downloadLink.href = window.URL.createObjectURL(updatedEpubBlob);
    downloadLink.download = metadata.title+'.epub';
    downloadLink.click();
    message.success("保存成功!")
  });
}

let   handleTableDom = (item)=>{
  let dom = getDom(item)
  if (!item.title.includes('ncx')){
    let tables = item.tables;
    tables.forEach(sub=>{
      let tableId = sub.id;
      let selector = `[tableId="${tableId}"]`;
      let table = dom.querySelector(selector);
      sub.tableConfig.forEach((tr,index)=>{
        //处理每一列
        if (tr.language === 'row'){
          let  trSelector = `td:nth-child(${index+1})`
          let tdList = table.querySelectorAll(trSelector);
          code(tdList);
        }
      })
    })
    item.content = dom.documentElement.outerHTML;
  }else{
  }
}
let  handleExport = ()=>{
  let   htmlData ={}
  docList.value.forEach(item=>{
    handleTableDom(item)
    htmlData[item.title]  = item.content
  })
  generateEpub(htmlData);
}
let      openWorker  = (dataList,startIndex) =>{
  const data = {
    'header': {
      'fn': 'auto_translation',
      'session': '',
      'client_key': 'browser-chrome-117.0.0-Windows 10-d516eec1-9db2-4f91-b521-c1c6a75451d1-1697843573656',
      'user': ''
    },
    'type': 'plain',
    'model_category': 'normal',
    'text_domain': 'general',
    'source': {
      'lang': 'en',
      'text_list': dataList
    },
    'target': {
      'lang': 'zh'
    }
  }
  let  topic ={
    data,
    topic:'translateNcxReplay'+v4()
  }

  window.ipcRenderer.send('translateNcx',topic)
  window.ipcRenderer.on(topic.topic, (event, res) => {
    console.log(startIndex, 'startIndex')
    let ncxContent = docList.value[htmlIndex.value ].content;
    res.auto_translation?.forEach((translate, index) => {
      const domIndex = startIndex +index
      let text = allNavPoint.value[domIndex].text;
      allNavPoint.value[domIndex].zh = translate


      ncxContent = ncxContent.replaceAll(`<text>${text}</text>`,`<text>${translate}</text>`)
    })
    total.value--
    docList.value[htmlIndex.value].content = ncxContent;
    if (total.value === 0){
      message.success("修改成功!")
    }
  });
};




let  handletranslateNcx = ()=>{
  let   htmlData =null;
  docList.value.forEach((item,index)=>{
    if (item.title.includes("ncx")){
      htmlData = item.content
      htmlIndex.value = index;
    }
  })
  const parser = new DOMParser()
  let dom = parser.parseFromString(htmlData, 'application/xml')
  let textList = dom.querySelectorAll("navPoint navLabel text");
  for (let i = 0; i < textList.length; i++) {
    let text  =textList[i];
    let  data ={
      text:text.textContent,
      zh:''
    }
    allNavPoint.value.push(data);
  }
  const dataIndexList = []
  let length = 0
  let startIndex = 0

  for (let i = 0; i < allNavPoint.value.length; i++) {
    const item =allNavPoint.value[i]
    const tempLength = length + item.text.length
    if (tempLength > 4900) {
      length = item.length
      total.value++
      openWorker(dataIndexList.map(item=>item.text),startIndex)
      startIndex = i
      length =0
      dataIndexList.splice(0)
    } else {
      length += item.text.length
      dataIndexList.push(item)
    }
  }
  total.value++
  openWorker(dataIndexList.map(item=>item.text),startIndex);
}









</script>
<style scoped >
/* For demo */
:deep(.slick-dots) {
  position: relative;
  height: auto;
}
:deep(.slick-slide img) {
  border: 5px solid #fff;
  display: block;
  margin: auto;
  max-width: 80%;
}
:deep(.slick-arrow) {
  display: none !important;
}
:deep(.slick-thumb) {
  bottom: 0px;
}
:deep(.slick-thumb li) {
  width: 60px;
  height: 45px;
}
:deep(.slick-thumb li img) {
  width: 100%;
  height: 100%;
  filter: grayscale(100%);
  display: block;
}
:deep .slick-thumb li.slick-active img {
  filter: grayscale(0%);
}

:deep .ant-tabs{
  max-height:calc(100vh - 420px) ;

}


.action{
  display: flex;
  text-align: left;
}
.fixed{
  flex:1
}
.countNumber{
  color: #ff0623;
}
main{
  display: flex;
  margin-top: 20px;
  height: calc(100vh - 120px);

}
.nav{
  width: 180px;
  overflow-y: scroll;
  user-select: none;
}
.title{
  padding: 10px 5px ;
  border-left: 1px solid  #4096ff;
  border-bottom: 1px solid  #4096ff;
  cursor: pointer;
}

.title:first-child{
  border-top: 1px solid  #4096ff;
}

.select{
  background: #4096ff;
  color: white;

}

.tableList {
  overflow-y: scroll;
  width: 640px;
}

.html_content{
  overflow-y: scroll;
  border-right: 1px solid  #4096ff;
  border-left: 1px solid  #4096ff;
  border-bottom: 1px solid  #4096ff;
  border-top: 1px solid  #4096ff;
  flex: 1;
  padding: 20px;
}


.table_wrapper {
  border: 1px  dashed #1677ff ;
  margin-top: 10px ;
  border-radius: 15px;
  padding: 10px;
}


.table_operate{
  padding: 10px;

  border-radius: 15px;

}

</style>
